package org.ws.httphelper.spring.registrar;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.util.Assert;
import org.ws.httphelper.builder.annotation.HttpOperation;

import java.util.Set;

public class HttpHelperClassPathScanner extends ClassPathScanningCandidateComponentProvider {

    private static Logger log = LoggerFactory.getLogger(HttpHelperClassPathScanner.class.getName());

    private BeanDefinitionRegistry registry;

    public HttpHelperClassPathScanner(BeanDefinitionRegistry registry) {
        this.registry = registry;
    }

    public void registerFilters() {
        // @HttpOperation
        addIncludeFilter(new AnnotationTypeFilter(HttpOperation.class));
    }

    @Override
    public Set<BeanDefinition> findCandidateComponents(String basePackage) {
        log.info("scan {}",basePackage);
        Set<BeanDefinition> candidateComponents = super.findCandidateComponents(basePackage);
        for (BeanDefinition candidateComponent : candidateComponents) {
            if (candidateComponent instanceof AnnotatedBeanDefinition) {
                AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent;
                AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
                Assert.isTrue(annotationMetadata.isInterface(),
                        "@HttpOperation can only be specified on an interface");
                processBeanDefinitions(this.registry,annotationMetadata);
            }
        }
        return candidateComponents;
    }


    private void processBeanDefinitions(BeanDefinitionRegistry registry,
                                     AnnotationMetadata annotationMetadata) {
        String className = annotationMetadata.getClassName();
        BeanDefinitionBuilder definition = BeanDefinitionBuilder
                .genericBeanDefinition(HttpHelperFactoryBean.class);
        definition.addPropertyValue("type",className);
        definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);

        AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();

        BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className);
        BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
    }

    @Override
    protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
        boolean isCandidate = false;
        if (beanDefinition.getMetadata().isIndependent()) {
            if (!beanDefinition.getMetadata().isAnnotation()) {
                isCandidate = true;
            }
        }
        return isCandidate;
    }
}
